package cn.jeina.utils.jcommander.utils;

import cn.jeina.utils.jcommander.BaseParameter;
import cn.jeina.utils.jcommander.ParameterEnum;
import cn.hutool.core.util.BooleanUtil;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterDescription;
import com.beust.jcommander.Strings;
import com.beust.jcommander.WrappedParameter;
import java.util.EnumSet;
import java.util.List;

/**
 * @author zhyu 2023-4-7 14:32
 * @version 1.0
 * @description
 */
@SuppressWarnings({"StringConcatenationInsideStringBufferAppend", "rawtypes"})
public class UsageUtil {

      public static final int maxNum = 67;

      public static String dealWrapLines(String words) {
            StringBuilder sb = new StringBuilder();
            String[] lines = words.split("(\r\n)|(\n\r)|\n|\r");
            for (int i = 0; i < lines.length; i++) {
                  sb.append(dealWrapLine(lines[i])).append("\n");
            }
            return sb.toString();
      }

      /**
       * 转折换行符
       */
      public static String dealWrapLine(String words) {
            int length = words.length();
            StringBuilder sb = new StringBuilder();
            if (length > maxNum) {
                  int index = 0;
                  int nowEnd = maxNum;
                  while (index < length) {
                        String row;
                        if (nowEnd < length) {
                              row = words.substring(index, nowEnd);
                        } else {
                              row = words.substring(index);
                        }
                        sb.append(row).append("\n");
                        index = nowEnd;
                        nowEnd += maxNum;
                  }
                  sb.deleteCharAt(sb.length() - 1);
                  return sb.toString();
            } else {
                  return words;
            }
      }

      public static void chineseUsage(BaseParameter params, JCommander jCommander) {
            StringBuilder sb = new StringBuilder("程序《");
            sb.append(params.getSoftwareName()).append("》说明文档\n");
            sb.append("\t文档说明: ").append(
                    "参数\"-m, -mode [必填][无值参数]\"就表示要在命令行输入\"-m\"后面跟空格和参数值, \",-mode\"表示这个参数也可以写成\"-mode\",他和\"-m\"是等效的, [必填]就是参数必填, [无值参数]表示写出参数名就可以了,不要值的。")
                .append("\n");
            sb.append("\t概览: ").append(params.getSoftwareDescription()).append("\n");
            sb.append("\t参数:\n");
            List<ParameterDescription> parameters = jCommander.getParameters();
            parameters.stream().filter(x -> !x.getParameter().hidden()).sorted((p0, p1) -> {
                  Parameter a0 = p0.getParameterAnnotation();
                  Parameter a1 = p1.getParameterAnnotation();
                  if (a0 != null && a0.order() != -1 && a1 != null && a1.order() != -1) {
                        return Integer.compare(a0.order(), a1.order());
                  } else if (a0 != null && a0.order() != -1) {
                        return -1;
                  } else if (a1 != null && a1.order() != -1) {
                        return 1;
                  } else {
                        return p0.getLongestName().compareTo(p1.getLongestName());
                  }
            }).forEach(
                x -> {
                      Class<?> type = x.getParameterized().getType();
                      int indentCount = 3;
                      WrappedParameter parameter = x.getParameter();
                      sb.append("\t\t").append(x.getNames()).append(" ");
                      if (parameter.required()) {
                            sb.append("[必填]");
                      }
                      if (BooleanUtil.isBoolean(type)) {
                            sb.append("[无值参数]");
                      }
                      sb.append("\n");
                      sb.append("\t\t\t描述: ").append(x.getDescription());
                      Object def = x.getDefault();
                      if (x.isDynamicParameter()) {
                            sb.append("\n" + s(indentCount))
                                .append("语法: " + parameter.names()[0]
                                    + "key" + parameter.getAssignment()
                                    + "value");
                      }
                      if (def != null && !x.isHelp()) {
                            String displayedDef = Strings.isStringEmpty(def.toString())
                                ? "<empty string>"
                                : def.toString();
                            sb.append("\n" + s(indentCount))
                                .append("默认: " + (parameter.password() ? "********" : displayedDef));
                      }
                      if (type.isEnum()) {
                            if (ParameterEnum.class.isAssignableFrom(type)) {
                                  sb.append("\n" + s(indentCount))
                                      .append("允许的值: " + getParameterEnumValue((Class<? extends ParameterEnum>) type));
                            } else {
                                  sb.append("\n" + s(indentCount))
                                      .append("允许的值: " + EnumSet.allOf((Class<? extends Enum>) type));
                            }
                      }
                      sb.append("\n");
                }
            );
            System.out.println(dealWrapLines(sb.toString()));
      }

      private static String getParameterEnumValue(Class<? extends ParameterEnum> clazz) {
            EnumSet enumSet = EnumSet.allOf((Class<? extends Enum>) clazz);
            StringBuilder sb = new StringBuilder();
            for (Object o : enumSet) {
                  ParameterEnum parameterEnum = (ParameterEnum) o;
                  sb.append(parameterEnum).append(": ").append(parameterEnum.getDescription()).append(",  ");
            }
            sb.deleteCharAt(sb.length() - 3);
            return sb.toString();
      }

      private static String s(int indent) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < indent; i++) {
                  sb.append("\t");
            }
            return sb.toString();
      }
}
